"""
系统目录管理 V2.0
完全符合实践要求：元数据存储、表结构管理
"""

import json
import struct
from typing import Dict, List, Optional, Any
from .page_storage_v2 import PageStorageSystem, TablePageManager

class SystemCatalog:
    """系统目录"""
    
    def __init__(self, storage_system: PageStorageSystem, table_manager: TablePageManager):
        """初始化系统目录"""
        self.storage = storage_system
        self.table_manager = table_manager
        self.catalog_table_name = "pg_catalog"
        self.tables = {}  # 表名 -> 表结构
        self.table_pages = {}  # 表名 -> 页面ID列表
        
        # 初始化系统目录表
        self._initialize_catalog()
    
    def _initialize_catalog(self):
        """初始化系统目录表"""
        # 创建系统目录表
        if not self.table_manager.create_table(self.catalog_table_name):
            # 如果已存在，加载数据
            self._load_catalog()
        else:
            # 新创建，初始化目录结构
            self._create_catalog_schema()
    
    def _create_catalog_schema(self):
        """创建系统目录表结构"""
        # 系统目录表结构：table_name, column_name, data_type, is_primary_key
        catalog_schema = {
            'columns': {
                'table_name': {'type': {'type': 'varchar', 'length': 100}},
                'column_name': {'type': {'type': 'varchar', 'length': 100}},
                'data_type': {'type': {'type': 'varchar', 'length': 50}},
                'is_primary_key': {'type': {'type': 'boolean'}},
                'column_order': {'type': {'type': 'int'}}
            },
            'primary_key': None
        }
        
        # 将系统目录表结构存储到内存中
        self.tables[self.catalog_table_name] = catalog_schema
    
    def _load_catalog(self):
        """从存储系统加载目录数据"""
        # 读取系统目录表的所有记录
        pages = self.table_manager.get_table_pages(self.catalog_table_name)
        
        for page_id in pages:
            page_data = self.storage.read_page(page_id)
            if page_data:
                records = self._parse_page_records(page_data, self.catalog_table_name)
                for record in records:
                    self._add_table_column_from_record(record)
    
    def _parse_page_records(self, page_data: bytearray, table_name: str) -> List[Dict]:
        """解析页面中的记录"""
        records = []
        record_count = struct.unpack('<I', page_data[0:4])[0]
        
        if record_count == 0:
            return records
        
        # 简化实现：假设记录是固定格式
        # 实际实现中需要根据表结构动态解析
        pos = 8  # 跳过页面头部
        
        for i in range(record_count):
            if pos + 200 > len(page_data):  # 假设每条记录最多200字节
                break
            
            # 解析记录（简化实现）
            record = self._parse_catalog_record(page_data, pos)
            if record:
                records.append(record)
                pos += 200  # 移动到下一条记录
        
        return records
    
    def _parse_catalog_record(self, page_data: bytearray, pos: int) -> Optional[Dict]:
        """解析系统目录记录"""
        try:
            # 简化实现：假设记录格式为固定长度字符串
            table_name = page_data[pos:pos+100].decode('utf-8').rstrip('\x00')
            column_name = page_data[pos+100:pos+200].decode('utf-8').rstrip('\x00')
            data_type = page_data[pos+200:pos+250].decode('utf-8').rstrip('\x00')
            is_primary_key = struct.unpack('<?', page_data[pos+250:pos+251])[0]
            column_order = struct.unpack('<i', page_data[pos+251:pos+255])[0]
            
            return {
                'table_name': table_name,
                'column_name': column_name,
                'data_type': data_type,
                'is_primary_key': is_primary_key,
                'column_order': column_order
            }
        except:
            return None
    
    def _add_table_column_from_record(self, record: Dict):
        """从记录添加表列信息"""
        table_name = record['table_name']
        column_name = record['column_name']
        
        if table_name not in self.tables:
            self.tables[table_name] = {
                'columns': {},
                'primary_key': None
            }
        
        # 解析数据类型
        if record['data_type'].startswith('varchar'):
            # 解析varchar(n)
            length = int(record['data_type'].split('(')[1].split(')')[0])
            data_type = {'type': 'varchar', 'length': length}
        else:
            data_type = {'type': record['data_type']}
        
        column_def = {
            'name': column_name,
            'type': data_type
        }
        
        if record['is_primary_key']:
            column_def['primary_key'] = True
            self.tables[table_name]['primary_key'] = column_name
        
        self.tables[table_name]['columns'][column_name] = column_def
    
    def create_table(self, table_name: str, schema: Dict) -> bool:
        """创建表并注册到系统目录"""
        if table_name in self.tables:
            return False
        
        # 创建表页面
        if not self.table_manager.create_table(table_name):
            return False
        
        # 注册表结构到系统目录
        self.tables[table_name] = schema
        
        # 将表结构写入系统目录表
        self._write_table_to_catalog(table_name, schema)
        
        return True
    
    def _write_table_to_catalog(self, table_name: str, schema: Dict):
        """将表结构写入系统目录表"""
        pages = self.table_manager.get_table_pages(self.catalog_table_name)
        
        for column_name, column_def in schema['columns'].items():
            # 创建目录记录
            record = {
                'table_name': table_name,
                'column_name': column_name,
                'data_type': self._format_data_type(column_def['type']),
                'is_primary_key': column_def.get('primary_key', False),
                'column_order': len(schema['columns'])
            }
            
            # 写入记录到系统目录表
            self._write_catalog_record(record, pages)
    
    def _format_data_type(self, data_type: Dict) -> str:
        """格式化数据类型为字符串"""
        if data_type['type'] == 'varchar':
            return f"varchar({data_type['length']})"
        else:
            return data_type['type']
    
    def _write_catalog_record(self, record: Dict, pages: List[int]):
        """写入目录记录到页面"""
        if not pages:
            # 如果没有页面，分配新页面
            page_id = self.table_manager.add_page_to_table(self.catalog_table_name)
            pages = [page_id]
        
        # 使用第一个页面
        page_id = pages[0]
        page_data = self.storage.read_page(page_id)
        
        if page_data:
            # 找到空闲位置
            record_count = struct.unpack('<I', page_data[0:4])[0]
            pos = 8 + record_count * 255  # 假设每条记录255字节
            
            # 写入记录
            self._write_record_to_page(page_data, record, pos)
            
            # 更新记录计数
            struct.pack_into('<I', page_data, 0, record_count + 1)
            
            # 写回页面
            self.storage.write_page(page_id, page_data)
    
    def _write_record_to_page(self, page_data: bytearray, record: Dict, pos: int):
        """将记录写入页面"""
        # 写入表名
        table_name_bytes = record['table_name'].encode('utf-8')[:100].ljust(100, b'\x00')
        page_data[pos:pos+100] = table_name_bytes
        
        # 写入列名
        column_name_bytes = record['column_name'].encode('utf-8')[:100].ljust(100, b'\x00')
        page_data[pos+100:pos+200] = column_name_bytes
        
        # 写入数据类型
        data_type_bytes = record['data_type'].encode('utf-8')[:50].ljust(50, b'\x00')
        page_data[pos+200:pos+250] = data_type_bytes
        
        # 写入主键标志
        struct.pack_into('<?', page_data, pos+250, record['is_primary_key'])
        
        # 写入列顺序
        struct.pack_into('<i', page_data, pos+251, record['column_order'])
    
    def drop_table(self, table_name: str) -> bool:
        """删除表并从系统目录中移除"""
        if table_name not in self.tables:
            return False
        
        # 删除表页面
        if not self.table_manager.drop_table(table_name):
            return False
        
        # 从内存中移除
        del self.tables[table_name]
        
        # 从系统目录表中删除记录
        self._remove_table_from_catalog(table_name)
        
        return True
    
    def _remove_table_from_catalog(self, table_name: str):
        """从系统目录表中删除表记录"""
        # 简化实现：重新构建系统目录表
        # 实际实现中应该只删除相关记录
        pages = self.table_manager.get_table_pages(self.catalog_table_name)
        
        for page_id in pages:
            page_data = self.storage.read_page(page_id)
            if page_data:
                # 清空页面
                page_data[8:] = b'\x00' * (len(page_data) - 8)
                struct.pack_into('<I', page_data, 0, 0)  # 重置记录计数
                self.storage.write_page(page_id, page_data)
        
        # 重新写入剩余的表
        for remaining_table_name, schema in self.tables.items():
            if remaining_table_name != self.catalog_table_name:
                self._write_table_to_catalog(remaining_table_name, schema)
    
    def get_table_schema(self, table_name: str) -> Optional[Dict]:
        """获取表结构"""
        return self.tables.get(table_name)
    
    def list_tables(self) -> List[str]:
        """列出所有表"""
        return [name for name in self.tables.keys() if name != self.catalog_table_name]
    
    def table_exists(self, table_name: str) -> bool:
        """检查表是否存在"""
        return table_name in self.tables
    
    def get_table_pages(self, table_name: str) -> List[int]:
        """获取表的页面列表"""
        return self.table_manager.get_table_pages(table_name)
    
    def add_page_to_table(self, table_name: str) -> int:
        """为表添加新页面"""
        return self.table_manager.add_page_to_table(table_name)
    
    def print_catalog(self):
        """打印系统目录"""
        print("系统目录:")
        for table_name, schema in self.tables.items():
            if table_name != self.catalog_table_name:
                print(f"  表: {table_name}")
                print(f"    主键: {schema.get('primary_key', 'None')}")
                print("    列:")
                for col_name, col_def in schema['columns'].items():
                    print(f"      {col_name}: {col_def['type']}")
    
    def get_catalog_info(self) -> Dict:
        """获取目录信息"""
        return {
            'table_count': len(self.list_tables()),
            'tables': self.tables,
            'catalog_table_name': self.catalog_table_name
        }

# 测试函数
if __name__ == "__main__":
    storage = PageStorageSystem("test_catalog")
    table_manager = TablePageManager(storage)
    catalog = SystemCatalog(storage, table_manager)
    
    print("测试系统目录管理...")
    
    # 测试创建表
    print("\n1. 测试创建表...")
    schema1 = {
        'columns': {
            'id': {'type': {'type': 'int'}, 'primary_key': True},
            'name': {'type': {'type': 'varchar', 'length': 50}},
            'age': {'type': {'type': 'int'}}
        },
        'primary_key': 'id'
    }
    
    success = catalog.create_table("student", schema1)
    print(f"创建表 'student': {'成功' if success else '失败'}")
    
    schema2 = {
        'columns': {
            'course_id': {'type': {'type': 'int'}, 'primary_key': True},
            'course_name': {'type': {'type': 'varchar', 'length': 100}},
            'credits': {'type': {'type': 'int'}}
        },
        'primary_key': 'course_id'
    }
    
    success = catalog.create_table("course", schema2)
    print(f"创建表 'course': {'成功' if success else '失败'}")
    
    # 测试查询表结构
    print("\n2. 测试查询表结构...")
    student_schema = catalog.get_table_schema("student")
    print(f"student表结构: {student_schema}")
    
    # 测试列出表
    print("\n3. 测试列出表...")
    tables = catalog.list_tables()
    print(f"所有表: {tables}")
    
    # 测试表存在性检查
    print("\n4. 测试表存在性检查...")
    print(f"student表存在: {catalog.table_exists('student')}")
    print(f"teacher表存在: {catalog.table_exists('teacher')}")
    
    # 打印目录信息
    print("\n5. 系统目录信息:")
    catalog.print_catalog()
    
    # 测试删除表
    print("\n6. 测试删除表...")
    success = catalog.drop_table("course")
    print(f"删除表 'course': {'成功' if success else '失败'}")
    
    print("\n7. 删除后的目录信息:")
    catalog.print_catalog()
